
import cv2
import numpy as np
from numpy.linalg import inv,lstsq
from numpy.linalg import matrix_rank as rank
#参考位置信息，（对其的标准位置）
REFERENCE_FACIAL_POINTS = np.array(
    [ [38.2946, 51.6963], 
    [73.5318, 51.5014], 
    [56.0252, 71.7366], 
    [41.5493, 92.3655], 
    [70.7299, 92.2041]],dtype = np.float32)

#计算相识变换的矩阵
def findNonreflectiveSimilarity(uv, xy, K=2): 
    """ 
        计算相似变换矩阵 
        其中 uv 是人脸检测的关键点；
            xy 是参考的标准关键点。
    """ 
    M = xy.shape[0]
    x = xy[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
    y = xy[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
    tmp1 = np.hstack((x, y, np.ones((M, 1)), np.zeros((M, 1))))
    tmp2 = np.hstack((y, -x, np.zeros((M, 1)), np.ones((M, 1))))
    X = np.vstack((tmp1, tmp2))
    u = uv[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
    v = uv[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
    U = np.vstack((u, v))
    # We know that X * r = U
    if rank(X) >= 2 * K:
        r, _, _, _ = lstsq(X, U, rcond=-1)
        r = np.squeeze(r)
    else:
        raise Exception('cp2tform:twoUniquePointsReq')
    sc = r[0]
    ss = r[1]
    tx = r[2]
    ty = r[3]
    Tinv = np.array([[sc, -ss, 0], [ss, sc, 0], [tx, ty, 1]])
    T = inv(Tinv)
    T[:, 2] = np.array([0, 0, 1])
    T = T[:, 0:2].T
    return T

#调研opencv的放射变换函数实现人脸对齐
def face_align(image,landmk):
    """
    image:原图
    landmk:人脸关键点
    """
    landmk = landmk.reshape((5,2))
    #计算变换矩阵
    M = findNonreflectiveSimilarity(landmk,REFERENCE_FACIAL_POINTS)
    #放射变换
    dst = cv2.warpAffine(image, M, (112,112))#参数：原图、变换矩阵，变换以后的图像大小
    return dst

if __name__ == "__main__":
    #人脸检测
    # from config import cfg_mnet
    from my_facedet import face_det

    # cfg = cfg_mnet
    
    #加载模型
    net = cv2.dnn.readNet("../models/FaceDetector.onnx")
    # net = RetinaFace(cfg=cfg_re50,phase = 'test')#搭建网络层
    # net = load_model(net,"./weights/Resnet50_Final.pth",True)#把训练好的参数放入网络层
    # net.eval()





    #读取图片
    image = cv2.imread("./curve/lyf1.jpg")
    #人脸检测
    dets ,landms = face_det(net,image)
    x1,y1,x2,y2,_ = np.int32(dets[0])
    
    face1 = image[y1:y2,x1:x2,0:3]
    #人脸对齐
    face2 = face_align(image,landms[0])

    #显示
    cv2.imshow("face1",face1)
    cv2.imshow("face2",face2)
    cv2.waitKey()

